//
//  PeripheralServiceViewController.swift
//  WCHBLEApp
//
//  Created by 娟华 胡 on 2021/3/18.
//

import UIKit
import SnapKit
import XappKit
import FGRoute
import XappBase
import CoreBluetooth

let SERVICE_UUID = "FFF0"
let READ_CHARACTER_UUID = "FFF1"
let WRITE_CHARACTER_UUID = "FFF2"
let CONFIG_CHARACTER_UUID = "FFF3"

class PeripheralServiceViewController: MH_VC_BaseViewController {
    @IBOutlet weak var segmentioView: Segmentio!
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var contentWidthLayout: NSLayoutConstraint!
    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var logContainView: UIView!
    
    private var serviceCharacter:[String:[CBCharacteristic]] = [String:[CBCharacteristic]]()
    private var characterReadView:CharacterReadView?
    private var characterWriteView:CharacterWriteView?
    
    //=================读取相关==============
    private var startRead:Bool = false
    private var readLength:Int64 = 0
    private var readStartTime:TimeInterval?

    //=================写入相关==============
    private var startWrite:Bool = false
    private var writeLength:Int64 = 0
    private var writeStartTime:TimeInterval?
    
    //======================================
    public var logView:LogView?
    public var services:[CBService] = [CBService]()
    public var serviceSendData:((Data, CBCharacteristic)->Void)?
    public var serviceNotify:((Bool, CBCharacteristic)->Void)?
    public var serviceReadData:((CBCharacteristic)->Void)?
    public var serviceDisConnect:(()->Void)?
    public var serviceLog:(()->Void)?
    public var serviceBackAction:(()->Void)?
    
    deinit {
        self.characterWriteView?.clearAction((Any).self)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        self.setupViews()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillAppear(animated)
        

        self.serviceDisConnect?()
        self.serviceBackAction?()
    }
    
    func setupViews() {
        self.tableView.delegate = self
        self.tableView.dataSource = self
        self.tableView.tableFooterView = UIView()
        self.tableView.estimatedRowHeight = 0
        self.tableView.estimatedSectionHeaderHeight = 0
        self.tableView.estimatedSectionFooterHeight = 0
        
        self.scrollView.delegate = self
        self.scrollView.isPagingEnabled = true
        self.contentWidthLayout.constant = UIScreen.main.bounds.width
        
        if (nil == self.logView) {
            self.logView = LogView.instanceFromNib()
        }
        self.logContainView.addSubview(self.logView!)
        self.logView?.snp.makeConstraints({ (make) in
            make.top.equalTo(0)
            make.left.equalTo(0)
            make.right.equalTo(0)
            make.bottom.equalTo(0)
        })
        
        self.segmentioView.setup(content: self.segmentioContent(), style: .onlyLabel, options:SegmentioBuilder.segmentioOptions(segmentioStyle: .onlyLabel))
        self.segmentioView.selectedSegmentioIndex = 0
        segmentioView.valueDidChange = { [weak self] _, segmentIndex in
            guard let wself = self else { return }
            
            let scrollViewWidth = wself.scrollView.frame.width
            let contentOffsetX = scrollViewWidth * CGFloat(segmentIndex)
            wself.scrollView.setContentOffset(
                CGPoint(x: contentOffsetX, y: 0),
                animated: true
            )

            if (segmentIndex == 1) {
                wself.serviceLog?()
            }
        }
    }
    
    private func segmentioContent() -> [SegmentioItem] {
        return [
            SegmentioItem(title: "Services", image: nil),
            SegmentioItem(title: "Log", image: nil),
        ]
    }

    public func servicesCharacterList(list:[String:[CBCharacteristic]]) {
        self.serviceCharacter = list
        self.tableView.reloadData()
    }
    
    private func showCharacterReadView(character:CBCharacteristic){
        if (nil == self.characterReadView) {
            self.characterReadView = CharacterReadView.instanceFromNib()
        }
        self.characterReadView?.textView.text = ""
        self.characterReadView?.clearReadCallBack = {[weak self] in
            guard let wself = self else { return }
            wself.clearReadStatus()
        }
        self.characterReadView?.notifyCallBack = {[weak self] (isOn) in
            guard let wself = self else { return }
            wself.serviceNotify?(isOn, character)
        }
        self.view.addSubview(self.characterReadView!)
        self.characterReadView?.snp.makeConstraints({ (make) in
            make.top.equalTo(0)
            make.left.equalTo(0)
            make.right.equalTo(0)
            make.bottom.equalTo(0)
        })
    }
    
    private func showCharacterWriteView() {
        if (nil == self.characterWriteView) {
            self.characterWriteView = CharacterWriteView.instanceFromNib()
        }
        self.characterWriteView?.textView.text = ""
        self.characterWriteView?.clearWriteCallBack = {[weak self] in
            guard let wself = self else { return }
            wself.clearWriteStatus()
        }
  
        self.view.addSubview(self.characterWriteView!)
        self.characterWriteView?.snp.makeConstraints({ (make) in
            make.top.equalTo(0)
            make.left.equalTo(0)
            make.right.equalTo(0)
            make.bottom.equalTo(0)
        })
    }
    
    public func readCharacterValue(character:CBCharacteristic?) {
        
        let uuid = character?.uuid.uuidString
        if (uuid == CONFIG_CHARACTER_UUID) {
            return
        }
        
        let data = character?.value
        if (nil == data) {
            return
        }
    
        if (!self.startRead) {
            self.startRead = true
            self.readLength = 0
            self.readStartTime = Date.init(timeIntervalSinceNow: 0).timeIntervalSince1970
        }
        
        let endTime = Date.init(timeIntervalSinceNow: 0).timeIntervalSince1970
        let time = endTime - (self.readStartTime ?? 0)
        self.readLength += Int64(data?.count ?? 0)
    
        var textStr = self.characterReadView?.textView.text ?? ""
        let dataStr = String.init(data: data!, encoding: .ascii)
        if (textStr.isEmpty) {
            textStr = dataStr ?? ""
        }else {
            textStr = textStr + "\n" + (dataStr ?? "")
        }
        self.characterReadView?.showTextContent(text: textStr)
        if (time > 0) {
            self.characterReadView?.showReadSpeed(totalLength: self.readLength, time: time)
        }
        
    }
    
    public func writeCount(count:Int64) {
        if (!self.startWrite) {
            self.startWrite = true;
            self.writeLength = 0
            self.writeStartTime = Date.init(timeIntervalSinceNow: 0).timeIntervalSince1970
        }
        
        let endTime = Date.init(timeIntervalSinceNow: 0).timeIntervalSince1970
        let time = endTime - (self.writeStartTime ?? 0)
        self.writeLength += count
        
        self.characterWriteView?.showWriteSpeed(totalLength: self.writeLength, time: time)
    }
    
    private func notifyAlter(character:CBCharacteristic) {
        let alter = UIAlertController.init(title: "订阅", message: "是否开启订阅", preferredStyle: .alert)
        let action1 = UIAlertAction.init(title: "开启", style: .default) {[weak self] (action) in
            guard let wself = self else {return}
            wself.serviceNotify?(true, character)
            
        }
        let action2 = UIAlertAction.init(title: "关闭", style: .cancel) {[weak self] (action) in
            guard let wself = self else {return}
            wself.serviceNotify?(false, character)
        }
        alter.addAction(action1)
        alter.addAction(action2)
        self.present(alter, animated: true, completion: nil)
    }
    
    private func clearReadStatus() {
        self.startRead = false
        self.readLength = 0
        self.readStartTime = 0
    }
    
    private func clearWriteStatus() {
        self.startWrite = false
        self.writeLength = 0
        self.writeStartTime = 0
    }
}

extension PeripheralServiceViewController:UITableViewDelegate, UITableViewDataSource {
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return services.count
    }
    
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 70
    }
    
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let headView = ServiceTableHeadView.instanceFromNib()
        if (services.count > section) {
            let service = services[section]
            headView?.updateServiceHead(service: service)
        }
        
        return headView
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 86
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if (services.count > section) {
            let service = services[section]
            let uuid = service.uuid.uuidString
            let characters = self.serviceCharacter[uuid]
            return characters?.count ?? 0
        }
        return 0
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCell(withIdentifier: "CharacteristicsTableViewCell") as? CharacteristicsTableViewCell
        if (cell == nil) {
            cell = CharacteristicsTableViewCell.instanceFromNib()
        }
        cell?.selectionStyle = .none
        if (self.services.count > indexPath.section) {
            let service = self.services[indexPath.section]
            let characters = self.serviceCharacter[service.uuid.uuidString]
            if ((characters?.count ?? 0) > indexPath.row) {
                cell?.updateCharactertics(character: characters![indexPath.row])
                
            }
            cell?.characterSend = {[weak self] in
                guard let wself = self else { return }
                wself.showCharacterWriteView()
                wself.characterWriteView?.sendData = {[weak self] (text) in
                    guard let wself = self else { return }
                    let data = text.data(using: .ascii) ?? Data()
                    wself.serviceSendData?(data, characters![indexPath.row])
                }
            }
            
            cell?.characterReceive =  {[weak self] in
                guard let wself = self else { return }
                wself.showCharacterReadView(character: characters![indexPath.row])
                
                wself.serviceReadData?(characters![indexPath.row])
            }
            
        }
        
        return cell ?? UITableViewCell()
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if (services.count > indexPath.section) {
            let service = services[indexPath.section]
            let uuid = service.uuid.uuidString
            let characters = self.serviceCharacter[uuid]
            
            if (characters?.count ?? 0) > indexPath.row {
                let character = characters?[indexPath.row]

            }
        }
    }
    
    private func showCharacterView(service:CBService, character:CBCharacteristic) {
        if service.uuid.uuidString == SERVICE_UUID {
            if character.uuid.uuidString == READ_CHARACTER_UUID {
                self.showCharacterReadView(character: character)
            }else if character.uuid.uuidString == WRITE_CHARACTER_UUID {
                self.showCharacterWriteView()
                self.characterWriteView?.sendData = {[weak self] (text) in
                    guard let wself = self else { return }
                    let data = text.data(using: .ascii) ?? Data()
                    wself.serviceSendData?(data, character)
                }
            }else if character.uuid.uuidString == CONFIG_CHARACTER_UUID {
                
            }
            
        }else {
            if (character.properties.contains(.read)) {
                self.showCharacterReadView(character: character)
            }else if ((character.properties.contains(.write) ) ||
                        (character.properties.contains(.writeWithoutResponse) )) {
                self.showCharacterWriteView()
                self.characterWriteView?.sendData = {[weak self] (text) in
                    guard let wself = self else { return }
                    let data = text.data(using: .ascii) ?? Data()
                    wself.serviceSendData?(data, character)
                }
            }else if (character.properties.contains(.notify)) {
                self.showCharacterReadView(character: character)
            }
        }
    }
}

extension PeripheralServiceViewController:UIScrollViewDelegate {
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        if (self.scrollView == scrollView) {
            let currentPage = floor(scrollView.contentOffset.x / scrollView.frame.width)
            segmentioView.selectedSegmentioIndex = Int(currentPage)
        }
    }
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if (self.scrollView == scrollView) {
            scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0)
        }
    }
}


